package com.ray.export.runner;

import com.ray.export.exception.DataRunnerException;
import com.ray.export.spring.ApplicationContextUtil;
import com.ray.export.strategy.async.BeforeAsync;
import com.ray.export.strategy.async.KeySuccessResult;
import com.ray.export.strategy.data.DataModel;
import com.ray.export.thread.ErrorThreadEvent;
import com.ray.export.thread.ThreadEvent;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;

/**
 * @author bo shen
 * @Description: 策略链条
 * @Class: RunnerChain
 * @Package com.ray.strategy
 * @date 2019/11/21 14:09
 * @company <p>杭州传化陆鲸科技有限公司</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Data
@Slf4j
public class RunnerChain {
    /**** 策略模板*/
    private Runner runner;
    /**
     * 下一级
     **/
    private RunnerChain next;

    public RunnerResult doChain(Annotation annotation, DataModel dataModel, RunnerResult perResult) {
        RunnerResult thisResult = runner.doRunner(annotation, dataModel, perResult);

        //执行错误回调 --单独执行
        if (!thisResult.getStatus()) {
            dataModel.setBeforeResult(thisResult.getResult());
            ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
            applicationContext.publishEvent(new ErrorThreadEvent(annotation,dataModel, thisResult));
            //启动一个异常任务
            if(!ObjectUtils.isEmpty(thisResult.getResult())){
                throw new DataRunnerException(thisResult.getResult().getMsg(),thisResult.getResult().getData());
            }else{
                throw new RuntimeException(String.format("链路执行异常:%s",runner.getClass()));
            }
        }

        //当下级不为空 或本级执行成功
        if (!ObjectUtils.isEmpty(next) && thisResult.getStatus() && !thisResult.isAsynchronou()) {
            dataModel.setBeforeResult(thisResult.getResult());
            RunnerResult result = next.doChain(annotation, dataModel, thisResult);
            result.setPer(thisResult);
            return result;
        }

        //启动异步流程
        if (thisResult.isAsynchronou()) {
            //启动异步调用 通过spring 事件驱动
            ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
            if (ObjectUtils.isEmpty(applicationContext)) {
                if (!ObjectUtils.isEmpty(next) && thisResult.getStatus()) {
                    dataModel.setBeforeResult(thisResult.getResult());
                    RunnerResult result = next.doChain(annotation, dataModel, thisResult);
                    result.setPer(thisResult);
                    return result;
                }
            } else {
                //异步执行前执行
                try {
                    RunnerResult before = beforeAsyncCall(annotation, dataModel, thisResult);
                    if (before.getStatus()) {
                        //启动一个异步线程
                        log.info("[{}]-执行异步任务", dataModel.getTemplateCode());
                        dataModel.setBeforeResult(before.getResult());
                        applicationContext.publishEvent(new ThreadEvent(annotation, dataModel, before, next));
                        //设置数据
                        KeySuccessResult keySuccessResult =(KeySuccessResult) before.getResult();
                        thisResult.getResult().setData(keySuccessResult.getKey());
                    } else {
                        throw new RuntimeException(before.getResult().getMsg());
                    }
                } catch (RuntimeException e) {
                    throw new RuntimeException(e.getMessage());
                } catch (Exception e1) {
                    throw new RuntimeException(e1.getMessage());
                }
            }
        }
        return thisResult;
    }

    private RunnerResult beforeAsyncCall(Annotation annotation, DataModel dataModel, RunnerResult result) {
        Runner runner = RunnerFactory.getRunner(BeforeAsync.class);
        return runner.doRunner(annotation, dataModel, result);
    }

}
